﻿using System.Text;
using Elsa.JavaScript.Models;
using Elsa.Workflows;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;
using Newtonsoft.Json;
using T.FAS.Runtime.MF.Activities.Helper;
using T.FAS.Runtime.MF.Entity;
using T.FAS.Runtime.MF.SPI;

namespace T.FAS.Runtime.MF.Activities.Nodes
{
    internal class IfElseNode : NodeBase, INodeMapper
    {
        [JsonProperty("data")]
        public new IfElseNodeData Data { get; set; }
        public List<Variable> Variables { get; set; } = new List<Variable>();
        public List<OutputDefinition> Outputs { get; set; }
        public List<InputDefinition> Inputs { get; set; } = new List<InputDefinition>();
        public IActivity MapToActivity()
        {
            var activity = new ConditionBranchActivity() { Id = Id, Name = Data.Label };
            var conditions = new List<BranchCondition>();
            var conditionDetails = new Dictionary<string,List<ConditionDetail>>();
            var ifElseCases = new List<string> { "if", "else" };
            
            foreach (var item in Data.Cases.Where(t => !ifElseCases.Contains(t.CaseID.ToLower())))
            {
                conditions.Add(new BranchCondition { Label = item.CaseID, Condition = JavaScriptExpression.Create(ParseJavaScriptExpression(item)) });
            }
            //添加IF
            var ifCase = Data.Cases.Find(t => t.CaseID.ToLower() == "if");
            if (ifCase!=null)
            {
                conditions.Insert(0, new BranchCondition { Label = ifCase.CaseID, Condition = JavaScriptExpression.Create(ParseJavaScriptExpression(ifCase)) });
            }

            ////添加ELSE
            //var elseCase = Data.Cases.Find(t => t.CaseID.ToLower() == "else");
            //if (elseCase != null)
            //{
            //    conditions.Add(new BranchCondition { Label = elseCase.CaseID, Condition = JavaScriptExpression.Create(ParseJavaScriptExpression(elseCase)) });
            //}
            foreach (var item in Data.Cases)
             {
                if (item.Conditions == null) continue;
                conditionDetails.Add(item.CaseID, ParseConditionDetail(item.Conditions));
            }
            activity.Conditions = conditions;
            activity.ConditionDetails = conditionDetails;
            activity.Metadata = DesignerMeta;

            return activity;
        }
        /// <summary>
        /// 此方法必须在
        /// </summary>
        /// <param name="conditions"></param>
        public List<ConditionDetail> ParseConditionDetail(List<ConditionNodeData> conditions)
        {
            var result = new List<ConditionDetail>();

            foreach (var condition in conditions)
            {
                var expectedValue = string.Empty;
                var expectedValueExpression = string.Empty;
                var actualValueExpression = ActivityHelper.GetVariableExpression(condition.Variable, condition.DataType, false);

                if (condition.ValueType.ToLower() == "constant")
                {
                     expectedValue = VariableHelper.ConvertConstantValue(condition.DataType, condition.ConstantValue);
                }
                else if (condition.ValueType.ToLower() == "variable")
                {
                     expectedValueExpression = ActivityHelper.GetVariableExpression(condition.VariableValue, condition.DataType,false);
                }

                result.Add(new ConditionDetail 
                {
                    ExpectedValueExpression= !string.IsNullOrEmpty(expectedValueExpression)? expectedValueExpression:"",
                    ExpectedValue = !string.IsNullOrEmpty(expectedValue) ? expectedValue : "",
                    ActualValueExpression = actualValueExpression,
                    ComparisonOperator = condition.Operator
                });
            }
            return result;
        }
        public string ParseJavaScriptExpression(CaseNodeData caseNode)
        {
            var sbScript = new StringBuilder();
            var conditions = caseNode.Conditions;

            if (conditions == null || conditions.Count() <= 0) return string.Empty;

            if (conditions.Any(t => t.Operator == "is_empty" || t.Operator == "is_not_empty"))
            {
                sbScript.AppendLine($@"function isEmpty(value) {{
                return value === null || 
                        value === undefined || 
                        value === """" ||
                        (Array.isArray(value) && value.length === 0) ||
                        (typeof value === 'object' && Object.keys(value).length === 0);
                 }}");
            }
            //将变量名称替换为真实的变量名称
            ReplaceAllVariableName(conditions);

            //生成变量定义的表达式
            var varaibleExprssions = GenerateVariableDefExpression(conditions);
            foreach (var expression in varaibleExprssions)
            {
                sbScript.AppendLine(expression);
            }

            //生成条件比较的表达式
            var compareExpressions = new List<string>();
            foreach (var condition in conditions)
            {
                var expression = GetCompareExpression(condition);
                if (!string.IsNullOrEmpty(expression))
                {
                    compareExpressions.Add(expression);
                }
            }
            sbScript.Append(string.Join($" {(caseNode.LogicalOperator.ToLower() == "and" ? "&&" : "||")} ", compareExpressions));


            return sbScript.ToString();
        }

        /// <summary>
        /// //将表达式中的变量替换为真实的变量名称
        /// </summary>
        /// <param name="conditions"></param>
        private void ReplaceAllVariableName(List<ConditionNodeData> conditions)
        {
            foreach (var condition in conditions)
            {
                //var varSelectors = condition.Variable.Split('.');
                //var varItem = varSelectors[0];

                ////从整个工作流中获取应的变量信息
                //var varInfo = (this.BelongTo.NodeInputOutputVariables ?? new List<UserVariable>()).Find(t => t.VariableName == varItem && t.ActivityID == condition.NodeID);
                //if (varInfo == null) { continue; }
                //var varName = varInfo.CompositeVarName;
                //varSelectors[0] = varName;
                //condition.Variable = string.Join(".", varSelectors);
                condition.Variable = ActivityHelper.GetSourceVariableRealName(this, condition.Variable, condition.NodeID);

                if (condition.ValueType == "variable")
                {

                    condition.VariableValue = ActivityHelper.GetSourceVariableRealName(this, condition.VariableValue, condition.VariableNodeID);
                    //varSelectors = condition.VariableValue.Split('.');
                    //varItem = varSelectors[0];
                    ////从整个工作流中获取应的变量信息
                    //varInfo = (this.BelongTo.NodeInputOutputVariables ?? new List<UserVariable>()).Find(t => t.VariableName == varItem && t.ActivityID == condition.VariableNodeID);
                    //varName = varInfo.CompositeVarName;
                    //varSelectors[0] = varName;
                    //condition.VariableValue = string.Join(".", varSelectors);
                }
            }
        }
        /// <summary>
        /// 生成定义变量的表达式
        /// </summary>
        /// <param name="conditions"></param>
        private static new List<string> GenerateVariableDefExpression(List<ConditionNodeData> conditions)
        {
            var generateVars = new List<string>();
            var expressions = new List<string>();
            //将左侧变量生成一个变量脚本
            foreach (var condition in conditions)
            {
                var varSelectors = condition.Variable.Split('.');
                var varItem = varSelectors[0];

                if (generateVars.Any(t => t.ToLower() == varItem.ToLower()) == false)
                {
                    /* if (varSelectors.Length > 1 || (varSelectors.Count() == 1 && condition.DataType == "record"))
                     {
                         expressions.Add($"let {varItem} = JSON.parse(variables.{varItem});");

                     }
                     else
                     {
                         expressions.Add($"let {varItem} = variables.{varItem};");
                     }*/
                    var expression = ActivityHelper.GetVariableExpression(condition.Variable, condition.DataType);
                    expressions.Add(expression);
                    generateVars.Add(varItem);
                }

            }
            //将右侧待比较的变量，生成一个变量脚本
            foreach (var condition in conditions.Where(t => t.ValueType == "variable"))
            {
                var varSelectors = condition.VariableValue.Split(".");

                var varName = varSelectors[0];
                if (generateVars.Any(t => t.ToLower() == varName.ToLower()) == false)
                {/*
                    if (varSelectors.Length > 1 || (varSelectors.Count() == 1 && condition.DataType == "record"))
                    {
                        expressions.Add($"let {varName} = JSON.parse(variables.{varName});");
                    }
                    else
                    {
                        expressions.Add($"let {varName} = variables.{varName};");
                    }*/

                    var expression = ActivityHelper.GetVariableExpression(condition.VariableValue, condition.DataType);
                    expressions.Add(expression);
                    generateVars.Add(varName);
                }
            }

            foreach (var condition in conditions)
            {
                //处理比较符左侧的值
                var varName = condition.Variable.Replace(".", "_");
                if (generateVars.Any(t => t.ToLower() == varName.ToLower()) == false)
                {
                    expressions.Add($"let {varName} = {VariableHelper.ConvertVariableValue(condition.DataType, condition.Variable)};");
                    generateVars.Add(varName);
                }
                //处理比较符右侧的变量值，常量不做处理，后面直接拼接
                if (condition.ValueType.ToLower() == "variable")
                {
                    varName = condition.VariableValue.Replace(".", "_");
                    if (generateVars.Any(t => t.ToLower() == varName.ToLower()) == false)
                    {
                        expressions.Add($"let {varName} = {VariableHelper.ConvertVariableValue(condition.DataType, condition.VariableValue)};");
                        generateVars.Add(varName);
                    }
                }
            }

            return expressions;
        }
        /// <summary>
        /// 生成条件表达式
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        private string GetCompareExpression(ConditionNodeData condition)
        {
            var varName = condition.Variable.Replace(".", "_");
            var compareValue = string.Empty;
            var expression = "";

            if (condition.ValueType.ToLower() == "constant")
            {
                compareValue = VariableHelper.ConvertConstantValue(condition.DataType, condition.ConstantValue);
            }
            else if (condition.ValueType.ToLower() == "variable")
            {
                compareValue = VariableHelper.ConvertVariableValue(condition.DataType, condition.VariableValue);
            }

            if (condition.Operator == "is_empty")
            {
                expression = $"(isEmpty({varName}) == true)";
            }
            else if (condition.Operator == "is_not_empty")
            {
                expression = $"(isEmpty({varName}) == false)";
            }
            else if (condition.Operator == "eq")
            {
                expression = $"({varName} == {compareValue})";
            }
            else if (condition.Operator == "neq")
            {
                expression = $"({varName} != {compareValue})";
            }
            else if (condition.Operator == "contains")
            {
                expression = $"({varName}.indexOf('{compareValue}')!=-1)";
            }
            else if (condition.Operator == "not_contains")
            {
                expression = $"({varName}.indexOf('{compareValue}')==-1)";
            }
            else if (condition.Operator == "starts_with")
            {
                expression = $"({varName}.startsWith('{compareValue}')==true)";
            }
            else if (condition.Operator == "ends_with")
            {
                expression = $"({varName}.endsWith('{compareValue}')==false)";
            }
            else if (condition.Operator == "matches")
            {
                expression = $"(/^{compareValue}$/.test({varName}))";
            }
            else if (condition.Operator == "gt")
            {
                expression = $"({varName} > {compareValue})";
            }
            else if (condition.Operator == "gte")
            {
                expression = $"({varName} >= {compareValue})";
            }
            else if (condition.Operator == "lt")
            {
                expression = $"({varName} < {compareValue})";
            }
            else if (condition.Operator == "lte")
            {
                expression = $"({varName} <= {compareValue})";
            }
            else if (condition.Operator == "before")
            {
                expression = $"({varName} < {compareValue})";
            }
            else if (condition.Operator == "after")
            {
                expression = $"({varName} > {compareValue})";
            }
            else if (condition.Operator == "not_before")
            {
                expression = $"({varName} >= {compareValue})";
            }
            else if (condition.Operator == "not_after")
            {
                expression = $"({varName} <= {compareValue})";
            }
            return expression;
        }
     
    }

   
    public class IfElseNodeData
    {
        [JsonProperty("label")]
        public string Label { get; set; }

        [JsonProperty("description")]
        public string Description { get; set; }
        [JsonProperty("falseLabel")]
        public string FalseLabel { get; set; }
        [JsonProperty("status")]
        public string Status { get; set; }
        [JsonProperty("trueLabel")]
        public string TrueLabel { get; set; }
        [JsonProperty("case")]
        public List<CaseNodeData> Cases { get; set; }
    }

    public class CaseNodeData
    {
        [JsonProperty("case_id")]
        public string CaseID { get; set; }

        [JsonProperty("id")]
        public string ID { get; set; }
        [JsonProperty("conditions")]
        public List<ConditionNodeData> Conditions { get; set; }

        [JsonProperty("label")]
        public string Label { get; set; }
        [JsonProperty("logical_operator")]
        public string LogicalOperator { get; set; }
    }

    public class ConditionNodeData
    {
        [JsonProperty("dataType")]
        public string DataType { get; set; }

        [JsonProperty("operator")]
        public string Operator { get; set; }

        //左侧比较的值
        [JsonProperty("nodeId")]
        public string NodeID { get; set; }

        [JsonProperty("variable")]
        public string Variable { get; set; }


        //右侧比较的值
        [JsonProperty("valueType")]
        public string ValueType { get; set; }

        [JsonProperty("constantValue")]
        public string ConstantValue { get; set; }

        [JsonProperty("variableId")]
        public string VariableID { get; set; }

        [JsonProperty("variableNodeId")]
        public string VariableNodeID { get; set; }

        [JsonProperty("variableValue")]
        public string VariableValue { get; set; }

        [JsonProperty("variableValueId")]
        public string VariableValueID { get; set; }

    }
}
